#include <string.h>
#include <stddef.h>
#include "lcd.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "ui.h"

#define LOG_TAG "UI"
#define LOG_LVL ELOG_LVL_INFO
#include "elog.h"

static QueueHandle_t ui_queue;

typedef enum
{
    UI_ACTION_COLOR_FILL = 1,
    UI_ACTION_SHOWCHAR,
    UI_ACTION_SHOWNUM,
    UI_ACTION_SHOWSTRING,
    UI_ACTION_SHOW_SELSIUS,
    UI_ACTION_SHOW_PICTURE,
    UI_ACTION_SHOW_CHINESE,
    UI_ACTION_SET_WINDOW,
    UI_ACTION_CLEAR,
} ui_action_t;

typedef struct
{
    ui_action_t action; // Action to perform
    union
    {
        struct
        {
            u16 sx; u16 sy; u16 ex; u16 ey; u16 color;          // Color to fill
        } color_fill;

        struct
        {
            u16 x; u16 y; u8 num; u8 size; u8 mode; u16 font_color; u16 back_color;
        } show_char;

        struct
        {
            u16 x; u16 y; u32 num; u8 len; u8 size; u16 font_Color; u16 back_color;
        } show_num;

        struct
        {
            u16 x; u16 y; u16 width; u16 height; u8 size; u8 *p; u16 font_color; u16 back_color;
        } show_string;

        struct
        {
            u16 x; u16 y; u8 size; u16 color; u16 back_color;
        } show_selsius;

        struct
        {
            u16 x; u16 y; u16 width; u16 height; const u16 *img;
        } show_picture;

        struct
        {
            u16 x; u16 y; const char *str; u8 size; u16 color; u16 bgcolor;
        } show_chinese;

        struct
        {
            u16 sx; u16 sy; u16 width; u16 height;
        } set_window;
        
        struct
        {
            u16 color;
        } clear;
    };
} ui_message_t;

void ui_function(void *param)
{
    ui_message_t ui_msg;
    
    LCD_Init();
    while (1)
    {
        xQueueReceive(ui_queue, &ui_msg, portMAX_DELAY);
        switch (ui_msg.action)
        {
            case UI_ACTION_COLOR_FILL:
                LCD_Color_Fill(ui_msg.color_fill.sx, ui_msg.color_fill.sy, ui_msg.color_fill.ex, ui_msg.color_fill.ey, ui_msg.color_fill.color);
                break;
            case UI_ACTION_SHOWCHAR:
                LCD_ShowChar(ui_msg.show_char.x, ui_msg.show_char.y, ui_msg.show_char.num, ui_msg.show_char.size, ui_msg.show_char.mode, ui_msg.show_char.font_color, ui_msg.show_char.back_color);
                break;
            case UI_ACTION_SHOWNUM:
                LCD_ShowNum(ui_msg.show_num.x, ui_msg.show_num.y, ui_msg.show_num.num, ui_msg.show_num.len, ui_msg.show_num.size, ui_msg.show_num.font_Color, ui_msg.show_num.back_color);
                break;
            case UI_ACTION_SHOWSTRING:
                LCD_ShowString(ui_msg.show_string.x, ui_msg.show_string.y, ui_msg.show_string.width, ui_msg.show_string.height, ui_msg.show_string.size, ui_msg.show_string.p, ui_msg.show_string.font_color, ui_msg.show_string.back_color);
                vPortFree((void*)ui_msg.show_string.p);
                break;
            case UI_ACTION_SHOW_SELSIUS:
                LCD_Show_Selsius(ui_msg.show_selsius.x, ui_msg.show_selsius.y, ui_msg.show_selsius.size, ui_msg.show_selsius.color, ui_msg.show_selsius.back_color);
                break;
            case UI_ACTION_SHOW_PICTURE:
                LCD_ShowPicture(ui_msg.show_picture.x, ui_msg.show_picture.y, ui_msg.show_picture.width, ui_msg.show_picture.height, ui_msg.show_picture.img);
                break;
            case UI_ACTION_SHOW_CHINESE:
                LCD_ShowChinese(ui_msg.show_chinese.x, ui_msg.show_chinese.y, ui_msg.show_chinese.str, ui_msg.show_chinese.size, ui_msg.show_chinese.color, ui_msg.show_chinese.bgcolor);
                vPortFree((void*)ui_msg.show_chinese.str);
                break;
            case UI_ACTION_SET_WINDOW:
                LCD_Set_Window(ui_msg.set_window.sx, ui_msg.set_window.sy, ui_msg.set_window.width, ui_msg.set_window.height);
                break;
            case UI_ACTION_CLEAR:
                LCD_Clear(ui_msg.clear.color);
                break;
            default: log_i("not ui pthread run"); break;
        }
    }
}

void UI_init(void)
{
    ui_queue = xQueueCreate(32, sizeof(ui_message_t));
    configASSERT(ui_queue);

    xTaskCreate(ui_function, "ui", 2048, NULL, 8, NULL);
}

void UI_Color_Fill(u16 sx, u16 sy, u16 ex, u16 ey, u16 color)
{
    ui_message_t ui_msg;
    ui_msg.action = UI_ACTION_COLOR_FILL;
    ui_msg.color_fill.sx = sx;
    ui_msg.color_fill.sy = sy;
    ui_msg.color_fill.ex = ex;
    ui_msg.color_fill.ey = ey;
    ui_msg.color_fill.color = color;
    xQueueSend(ui_queue, &ui_msg, portMAX_DELAY);
}

void UI_ShowChar(u16 x, u16 y, u8 num, u8 size, u8 mode, u16 font_color, u16 back_color)
{
    ui_message_t ui_msg;
    ui_msg.action = UI_ACTION_SHOWCHAR;
    ui_msg.show_char.x = x;
    ui_msg.show_char.y = y;
    ui_msg.show_char.num = num;
    ui_msg.show_char.size = size;
    ui_msg.show_char.mode = mode;
    ui_msg.show_char.font_color = font_color;
    ui_msg.show_char.back_color = back_color;
    xQueueSend(ui_queue, &ui_msg, portMAX_DELAY);
}

void UI_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size, u16 font_Color, u16 back_color)
{
    ui_message_t ui_msg;
    ui_msg.action = UI_ACTION_SHOWNUM;
    ui_msg.show_num.x = x;
    ui_msg.show_num.y = y;
    ui_msg.show_num.num = num;
    ui_msg.show_num.len = len;
    ui_msg.show_num.size = size;
    ui_msg.show_num.font_Color = font_Color;
    ui_msg.show_num.back_color = back_color;
    xQueueSend(ui_queue, &ui_msg, portMAX_DELAY);
}

void UI_ShowString(u16 x, u16 y, u16 width, u16 height, u8 size, u8 *p, u16 font_color, u16 back_color)
{
    char *pstr = pvPortMalloc(strlen((char*)p) + 1);
    if (pstr == NULL)
    {
        log_e("Show string is pvPortMalloc failed");
        return;
    }
    strcpy(pstr, (const char*)p);

    ui_message_t ui_msg;
    ui_msg.action = UI_ACTION_SHOWSTRING;
    ui_msg.show_string.x = x;
    ui_msg.show_string.y = y;
    ui_msg.show_string.width = width;
    ui_msg.show_string.height = height;
    ui_msg.show_string.size = size;
    ui_msg.show_string.p = (uint8_t*)pstr;
    ui_msg.show_string.font_color = font_color;
    ui_msg.show_string.back_color = back_color;
    xQueueSend(ui_queue, &ui_msg, portMAX_DELAY);
}

void UI_Show_Selsius(u16 x, u16 y, u8 size, u16 color, u16 back_color)
{
    ui_message_t ui_msg;
    ui_msg.action = UI_ACTION_SHOW_SELSIUS;
    ui_msg.show_selsius.x = x;
    ui_msg.show_selsius.y = y;
    ui_msg.show_selsius.size = size;
    ui_msg.show_selsius.color = color;
    ui_msg.show_selsius.back_color = back_color;
    xQueueSend(ui_queue, &ui_msg, portMAX_DELAY);
}

void UI_ShowPicture(u16 x, u16 y, u16 width, u16 height, const u16 *img)
{
    ui_message_t ui_msg;
    ui_msg.action = UI_ACTION_SHOW_PICTURE;
    ui_msg.show_picture.x = x;
    ui_msg.show_picture.y = y;
    ui_msg.show_picture.width = width;
    ui_msg.show_picture.height = height;
    ui_msg.show_picture.img = img;
    xQueueSend(ui_queue, &ui_msg, portMAX_DELAY);
}

void UI_ShowChinese(uint16_t x, uint16_t y, const char *str, u8 size, uint16_t color, uint16_t bgcolor)
{
    char *pstr = pvPortMalloc(strlen(str) + 1);
    if (pstr == NULL)
    {
        log_e("Show chinese is pvPortMalloc failed");
        return;
    }
    strcpy(pstr, str);

    ui_message_t ui_msg;
    ui_msg.action = UI_ACTION_SHOW_CHINESE;
    ui_msg.show_chinese.x = x;
    ui_msg.show_chinese.y = y;
    ui_msg.show_chinese.str = pstr;
    ui_msg.show_chinese.size = size;
    ui_msg.show_chinese.color = color;
    ui_msg.show_chinese.bgcolor = bgcolor;
    xQueueSend(ui_queue, &ui_msg, portMAX_DELAY);
}

void UI_Set_Window(u16 sx,u16 sy,u16 width,u16 height)
{
    ui_message_t ui_msg;
    ui_msg.action = UI_ACTION_SET_WINDOW;
    ui_msg.show_picture.x = sx;
    ui_msg.show_picture.y = sy;
    ui_msg.show_picture.width = width;
    ui_msg.show_picture.height = height;
    xQueueSend(ui_queue, &ui_msg, portMAX_DELAY);
}

void UI_Clear(u16 color)
{
    ui_message_t ui_msg;
    ui_msg.action = UI_ACTION_CLEAR;
    ui_msg.clear.color = color;
    xQueueSend(ui_queue, &ui_msg, portMAX_DELAY);
}
